﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using HengTong.Model.Db.Hr;
using HengTong.Model.Db.Hr.Attendance;
using HengTong.Model.Extension;
using HengTong.Model.Util;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using TiaoTaoHelper.Wtm.Services;
using UUIDNext;
using WalkingTec.Mvvm.Core.Support.Quartz;

namespace HengTong.Tasks
{
    /// <summary>
    /// 海康威视门禁打卡记录自动导入任务
    /// </summary>
    [Display(Name = "海康门禁打卡记录导入", Description = "每天自动导入昨天的海康门禁打卡记录")]
    [QuartzRepeat(3600 * 24, 0, true, 60 * 5)] // 每天执行一次，延迟5分钟启动
    public class ImportHikVisionAttendanceTask : BaseTask<ImportHikVisionAttendanceTask>
    {
        // 批处理大小
        private const int BatchSize = 50;

        // 每页大小
        private const int PageSize = 1000;

        // 需要过滤的设备编码(正门岗)
        private static readonly HashSet<string> ExcludedDeviceIds = new HashSet<string>
        {
            "0bbe2e278a73483b9a4b27b98f2a37ec", // 正门岗出_门_1
            "5e84e2f77bc0480b91fd3757f5e6663b" // 正门岗进_门_1
        };

        protected override async Task<bool> ExecuteStart()
        {
            var startTime = DateTime.Now;
            Logger.LogInformation($"开始导入昨天门禁打卡记录 - {startTime:yyyy-MM-dd HH:mm:ss}");

            // 获取配置
            var siteConfig = Wtm.GetSiteConfig();
            var siteConfigControlConfig = siteConfig.ControlConfig;
            if (string.IsNullOrWhiteSpace(siteConfigControlConfig))
            {
                Logger.LogError("系统JSON配置未设置，请在系统配置中填写相关参数");
                return false;
            }

            try
            {
                // 解析JSON配置
                var config = JsonSerializer.Deserialize<Dictionary<string, Dictionary<string, string>>>(
                    siteConfigControlConfig);

                // 获取海康威视配置
                if (!config.TryGetValue("HikVision", out var hikConfig) ||
                    !hikConfig.TryGetValue("Host", out string host) ||
                    !hikConfig.TryGetValue("AppKey", out string appKey) ||
                    !hikConfig.TryGetValue("AppSecret", out string appSecret))
                {
                    Logger.LogError("海康威视配置不完整，请检查系统配置");
                    return false;
                }

                Logger.LogInformation($"海康配置信息 - Host: {host}, AppKey: {appKey}");


                var hostParts = host.Split(':');
                string ip = hostParts[0];
                int port = int.Parse(hostParts[1]);

                // 设置平台信息
                HikVisionHttpUtil.SetPlatformInfo(appKey, appSecret, ip, port, true);

                // 获取昨天的时间范围（整天）
                DateTime yesterday = DateTime.Now.AddDays(-1).Date;
                string startTimeStr = yesterday.ToString("yyyy-MM-ddT00:00:00+08:00");
                string endTimeStr = yesterday.AddDays(1).AddSeconds(-1).ToString("yyyy-MM-ddT23:59:59+08:00");

                Logger.LogInformation("查询时间范围: {StartTime} 至 {EndTime}", startTimeStr, endTimeStr);

                // 查询已导入的记录EventId
                Logger.LogInformation("查询已导入的记录...");
                var existingEvents = await Wtm.DC.Set<SysAttendanceRawRecord>()
                    .Where(r => r.PunchTime >= yesterday && r.PunchTime < yesterday.AddDays(1))
                    .Where(r => r.RawData != null && r.RawData.Contains("EventId"))
                    .Select(r => r.RawData)
                    .ToListAsync();

                // 提取EventId
                var existingEventIds = new HashSet<string>();
                foreach (var rawData in existingEvents)
                {
                    try
                    {
                        var hikEvent = JsonSerializer.Deserialize<AcsDoorEvent>(rawData);
                        if (hikEvent != null && !string.IsNullOrEmpty(hikEvent.EventId))
                        {
                            existingEventIds.Add(hikEvent.EventId);
                        }
                    }
                    catch (Exception ex)
                    {
                        Logger.LogWarning(ex, "解析已存在记录的EventId失败: {RawData}", rawData);
                    }
                }

                Logger.LogInformation("找到 {Count} 条已导入的记录", existingEventIds.Count);

                // 预加载员工信息，处理重复工号情况
                Logger.LogInformation("预加载员工信息...");
                var personList = await Wtm.DC.Set<SysPerson>()
                    .Where(x => x.GetType() == typeof(SysPerson))
                    .Where(p => p.StaffNo != null && p.StaffNo != "")
                    .ToListAsync();

                // 创建工号到人员的映射字典
                var personDict = personList.ToDictionary(p => p.StaffNo, p => p);
                Logger.LogInformation($"加载了 {personList.Count} 条员工信息");

                // 分页查询参数
                int pageNo = 1;
                bool hasMorePages = true;
                int totalRecords = 0;
                int imported = 0;
                int skipped = 0;
                int failed = 0;
                int personMatched = 0;
                int personNotMatched = 0;

                // 分页查询所有门禁记录
                while (hasMorePages)
                {
                    // 创建请求参数
                    var requestParams = new
                    {
                        pageNo = pageNo,
                        pageSize = PageSize,
                        startTime = startTimeStr,
                        endTime = endTimeStr,
                        sort = "eventTime",
                        order = "desc"
                    };

                    string jsonBody = JsonSerializer.Serialize(requestParams);
                    Logger.LogInformation("请求参数: 页码={PageNo}, 页大小={PageSize}", pageNo, PageSize);

                    string uri = "/artemis/api/acs/v2/door/events";

                    try
                    {
                        // 调用API
                        var response =
                            await HikVisionHttpUtil.HttpPostJsonAsync<AcsDoorEventResponse>(uri, jsonBody);

                        // 检查响应
                        if (response != null && response.Code == "0" && response.Data != null)
                        {
                            totalRecords = response.Data.Total;
                            int totalPages = (totalRecords + PageSize - 1) / PageSize;

                            Logger.LogInformation("获取第 {PageNo}/{TotalPages} 页数据，总记录数: {Total}",
                                pageNo, totalPages, totalRecords);

                            // 仅处理有工号且不是正门岗的记录，减少内存占用
                            var validEvents = response.Data.List
                                .Where(e => !string.IsNullOrEmpty(e.jobNo) && // 过滤工号为空
                                            !ExcludedDeviceIds.Contains(e.DevIndexCode)) // 过滤正门岗设备
                                .ToList();

                            Logger.LogInformation("本页有效记录(有工号且非正门岗): {Count}/{PageSize}",
                                validEvents.Count, response.Data.List.Count);

                            // 批量处理记录
                            var recordBatch = new List<SysAttendanceRawRecord>(BatchSize);

                            foreach (var hikEvent in validEvents)
                            {
                                try
                                {
                                    // 检查是否已存在
                                    if (existingEventIds.Contains(hikEvent.EventId))
                                    {
                                        skipped++;
                                        continue;
                                    }

                                    // 添加到已处理集合，避免重复处理
                                    existingEventIds.Add(hikEvent.EventId);

                                    // 根据工号查找对应员工
                                    personDict.TryGetValue(hikEvent.jobNo, out var person);

                                    // 创建打卡记录
                                    var attendanceRecord = new SysAttendanceRawRecord
                                    {
                                        ID = Uuid.NewDatabaseFriendly(Database.SqlServer),
                                        PersonId = person?.ID, // 如果找到人员则关联，否则为null
                                        StaffNo = hikEvent.jobNo, // 保存原始工号，便于后续处理
                                        PunchTime = DateTime.Parse(hikEvent.EventTime),
                                        DeviceId = hikEvent.DevIndexCode,
                                        DeviceName = hikEvent.DoorName, // 使用DoorName作为设备名称
                                        Location = hikEvent.DoorName,
                                        PunchType = hikEvent.InAndOutType == 1 ? "进" :
                                            hikEvent.InAndOutType == 0 ? "出" : "未知",
                                        RecognitionType = "海康威视打卡",
                                        RawData = JsonSerializer.Serialize(hikEvent),
                                        ProcessStatus = person != null ? "已匹配人员" : "未匹配人员",
                                        ProcessTime = DateTime.Now,
                                        Remark = person != null
                                            ? $"已匹配到人员：{person.Name}"
                                            : $"未匹配到人员，原始姓名：{hikEvent.PersonName}，工号：{hikEvent.jobNo}"
                                    };

                                    recordBatch.Add(attendanceRecord);

                                    // 统计
                                    if (person != null)
                                        personMatched++;
                                    else
                                        personNotMatched++;

                                    // 批量保存
                                    if (recordBatch.Count >= BatchSize)
                                    {
                                        await Wtm.DC.Set<SysAttendanceRawRecord>().AddRangeAsync(recordBatch);
                                        await Wtm.DC.SaveChangesAsync();

                                        imported += recordBatch.Count;
                                        Logger.LogInformation("已导入 {Count} 条记录", imported);

                                        recordBatch.Clear();
                                    }
                                }
                                catch (Exception ex)
                                {
                                    failed++;
                                    Logger.LogError(ex, "处理记录失败，EventId: {EventId}, 工号: {JobNo}",
                                        hikEvent.EventId, hikEvent.jobNo);
                                }
                            }

                            // 保存剩余记录
                            if (recordBatch.Count > 0)
                            {
                                await Wtm.DC.Set<SysAttendanceRawRecord>().AddRangeAsync(recordBatch);
                                await Wtm.DC.SaveChangesAsync();

                                imported += recordBatch.Count;
                                recordBatch.Clear();
                            }

                            // 判断是否还有下一页
                            if (pageNo >= totalPages || response.Data.List.Count < PageSize)
                            {
                                hasMorePages = false;
                            }
                            else
                            {
                                pageNo++;
                            }

                            // 清理本页数据，减少内存占用
                            response.Data.List.Clear();
                            GC.Collect();
                        }
                        else
                        {
                            Logger.LogError("API返回错误: {Code} - {Message}",
                                response?.Code ?? "NULL", response?.Msg ?? "请求失败");
                            hasMorePages = false;
                            return false;
                        }
                    }
                    catch (Exception ex)
                    {
                        Logger.LogError(ex, "查询海康威视API失败，页码: {PageNo}", pageNo);

                        // 重试最多3次，然后继续下一页
                        if (++pageNo > 3)
                            hasMorePages = false;
                    }
                }

                // 输出统计信息
                TimeSpan duration = DateTime.Now - startTime;
                Logger.LogInformation("导入完成! 总耗时: {Duration:mm\\:ss}, 总记录数: {Total}",
                    duration, totalRecords);
                Logger.LogInformation("成功导入: {Imported}, 跳过已存在: {Skipped}, 失败: {Failed}",
                    imported, skipped, failed);
                Logger.LogInformation("人员匹配: {Matched}, 未匹配: {Unmatched}",
                    personMatched, personNotMatched);

                return true;
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, "导入门禁打卡记录过程中发生异常");
                return false;
            }
        }
    }

    /// <summary>
    /// 门禁事件查询响应模型
    /// </summary>
    public class AcsDoorEventResponse
    {
        /// <summary>
        /// 返回码，0表示成功
        /// </summary>
        public string Code { get; set; }

        /// <summary>
        /// 返回信息
        /// </summary>
        public string Msg { get; set; }

        /// <summary>
        /// 返回数据
        /// </summary>
        public AcsDoorEventData Data { get; set; }
    }

    /// <summary>
    /// 门禁事件数据
    /// </summary>
    public class AcsDoorEventData
    {
        /// <summary>
        /// 总数
        /// </summary>
        public int Total { get; set; }

        /// <summary>
        /// 当前页码
        /// </summary>
        public int PageNo { get; set; }

        /// <summary>
        /// 每页大小
        /// </summary>
        public int PageSize { get; set; }

        /// <summary>
        /// 事件列表
        /// </summary>
        public List<AcsDoorEvent> List { get; set; }
    }

    /// <summary>
    /// 门禁事件详情
    /// </summary>
    public class AcsDoorEvent
    {
        /// <summary>
        /// 事件ID
        /// </summary>
        public string EventId { get; set; }

        /// <summary>
        /// 事件名称
        /// </summary>
        public string EventName { get; set; }

        /// <summary>
        /// 事件时间
        /// </summary>
        public string EventTime { get; set; }

        /// <summary>
        /// 人员ID
        /// </summary>
        public string PersonId { get; set; }

        /// <summary>
        /// 卡号
        /// </summary>
        public string CardNo { get; set; }

        /// <summary>
        /// 人员姓名
        /// </summary>
        public string PersonName { get; set; }

        /// <summary>
        /// 工号
        /// </summary>
        public string jobNo { get; set; }

        /// <summary>
        /// 组织编码
        /// </summary>
        public string OrgIndexCode { get; set; }

        /// <summary>
        /// 组织名称
        /// </summary>
        public string OrgName { get; set; }

        /// <summary>
        /// 门禁点名称
        /// </summary>
        public string DoorName { get; set; }

        /// <summary>
        /// 门禁点编码
        /// </summary>
        public string DoorIndexCode { get; set; }

        /// <summary>
        /// 门禁点所在区域编码
        /// </summary>
        public string DoorRegionIndexCode { get; set; }

        /// <summary>
        /// 抓拍图片地址
        /// </summary>
        public string PicUri { get; set; }

        /// <summary>
        /// 图片存储服务的唯一标识
        /// </summary>
        public string SvrIndexCode { get; set; }

        /// <summary>
        /// 事件类型
        /// </summary>
        public int EventType { get; set; }

        /// <summary>
        /// 进出类型(1：进 0：出 -1:未知)
        /// </summary>
        public int InAndOutType { get; set; }

        /// <summary>
        /// 读卡器唯一标识
        /// </summary>
        public string ReaderDevIndexCode { get; set; }

        /// <summary>
        /// 读卡器名称
        /// </summary>
        public string ReaderDevName { get; set; }

        /// <summary>
        /// 控制器设备编码
        /// </summary>
        public string DevIndexCode { get; set; }

        /// <summary>
        /// 控制器设备名称
        /// </summary>
        public string DevName { get; set; }

        /// <summary>
        /// 身份证图片地址
        /// </summary>
        public string IdentityCardUri { get; set; }

        /// <summary>
        /// 事件入库时间
        /// </summary>
        public string ReceiveTime { get; set; }

        /// <summary>
        /// 学号
        /// </summary>
        public string StudentId { get; set; }

        /// <summary>
        /// 证件号码
        /// </summary>
        public string CertNo { get; set; }
    }
}